package cn.js.sangu.unitStore.service.process;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import cn.js.sangu.unitStore.common.exception.ServiceException;
import cn.js.sangu.unitStore.entity.BomDe;
import cn.js.sangu.unitStore.entity.BomEntity;
import cn.js.sangu.unitStore.entity.CodeLib;
import cn.js.sangu.unitStore.entity.User;
import cn.js.sangu.unitStore.service.BomDeService;
import cn.js.sangu.unitStore.service.CodeLibService;
import cn.js.sangu.unitStore.utils.TokenUtils;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class ExcelService {

    String repairMsg = " 请联系林硕修复 ";

    @Autowired
    private BomDeService bomDeService;

    @Autowired
    private CodeLibService codeLibService;

    @Autowired
    AutoCodeProcessService autoCodeProcessService;

    @Autowired
    PartAttributesCheck partAttributesCheck; // 零件属性检查，包含编码前和编码后

    public String dataProcess(String filePath, BomEntity param) {
        try {
            // 判断文件路径是否为空
            if (filePath == null || filePath.trim().isEmpty()) {
                log.error("文件路径为空");
                throw new ServiceException("文件路径不能为空" + repairMsg);
            }

            File file = new File(filePath);

            // 判断文件是否存在
            if (!file.exists()) {
                log.error("文件不存在: {}", filePath);
                throw new ServiceException("文件不存在" + repairMsg);
            }

            // 判断是否为Excel文件
            String fileName = file.getName().toLowerCase();
            if (!fileName.endsWith(".xls") && !fileName.endsWith(".xlsx")) {
                log.error("不是Excel文件: {}", filePath);
                throw new ServiceException("不是Excel格式文件" + repairMsg);
            }

            // 读取Excel数据
            List<BomDe> bomDeList = readExcelData(file, param);

            log.info("从Excel文件中读取到 {} 条有效数据", bomDeList.size());

            if (bomDeList.isEmpty()) {
                log.warn("Excel文件中没有有效数据");
                throw new ServiceException("Excel文件中没有有效数据" + repairMsg);
            }

            // 在保存数据之前先去重
            log.info("开始去重操作，原始数据 {} 条", bomDeList.size());
            // 调用去重方法进行数据去重
            List<BomDe> deduplicatedList = deduplicateData(bomDeList, param);
            // 用户勾选自动编码时，才会执行编码逻辑
            Boolean autoCode = param.getAutoCode();

            if (autoCode != null && autoCode) {
                // 执行任务前更新Map数据
                autoCodeProcessService.updateMapsBeforeTask();

                // 根据去重类型决定是否使用codeCache
                // 当去重类型为"part"时，deduplicateData已确保tuhao,name,cailiao,guige,leibie组合唯一，无需缓存
                // 当去重类型为"project"时，去重还考虑了zongjishu字段，可能存在相同tuhao,name,cailiao,guige,leibie但不同zongjishu的记录，此时缓存仍有意义
                String deWeightType = param.getDeWeightType();
                if ("project".equals(deWeightType)) {
                    // 使用缓存优化性能
                    Map<String, String> codeCache = new HashMap<>();
                    for (BomDe bomDe : deduplicatedList) {
                        // 创建与generateCode方法中查询条件一致的缓存键
                        String cacheKey = (bomDe.getTuhao() != null ? bomDe.getTuhao().trim() : "NULL_TUHAO") + "_" +
                                (bomDe.getName() != null ? bomDe.getName().trim() : "NULL_NAME") + "_" +
                                (bomDe.getCailiao() != null ? bomDe.getCailiao().trim() : "NULL_CAILIAO") + "_" +
                                (bomDe.getGuige() != null ? bomDe.getGuige() : "NULL_GUIGE") + "_" +
                                (bomDe.getLeibie() != null ? bomDe.getLeibie() : "NULL_LEIBIE");

                        // 优先使用内存缓存，减少重复的数据库查询
                        String cachedCode = codeCache.get(cacheKey);
                        if (cachedCode != null) {
                            bomDe.setSyscode(cachedCode);
                        } else {
                            // 调用generateCode方法生成编码（内部会检查code_lib表）
                            String newCode = autoCodeProcessService.generateCode(bomDe, param.getCreator(), "项目批次");
                            bomDe.setSyscode(newCode);
                            codeCache.put(cacheKey, newCode);
                        }
                    }
                } else {
                    // 去重类型为"part"时，直接生成编码，无需缓存
                    for (BomDe bomDe : deduplicatedList) {
                        String newCode = autoCodeProcessService.generateCode(bomDe, param.getCreator(), "零件批次");
                        bomDe.setSyscode(newCode);
                    }
                }
                log.info("已为 {} 条数据生成编码", deduplicatedList.size());
                // 以下 校验和更新到码库动作，已经在
                // 生成编码后，调用检查方法，校验编码格式是否正确，是否有重复项等检查
                // partAttributesCheck.validateAndFixCodes(deduplicatedList);
                // 新数据更新到编码历史库
                // updateCodeHistoryLibrary(deduplicatedList);
            } else {
                log.info("未开启自动编码功能，跳过编码生成步骤");
            }

            // 在保存数据之前先清空老数据，通过List传参，无需通过BomDe表。
            // log.info("开始清空bom_de表中的老数据并重置自增ID");
            // if (bomDeService.truncateTable()) {
            // log.info("成功清空bom_de表中的所有老数据并重置自增ID");
            // } else {
            // log.warn("清空bom_de表中的老数据并重置自增ID时出现问题");
            // }

            // 批量保存去重后的数据到数据库
            // if (bomDeService.saveBatch(deduplicatedList)) {
            // log.info("成功保存 {} 条去重后的数据到数据库", deduplicatedList.size());
            // } else {
            // log.error("保存数据到数据库失败");
            // throw new ServiceException("保存数据到数据库失败" + repairMsg);
            // }

            // 将处理后的数据写入到新的sheet页，直接传入去重后的数据列表，避免再次从数据库查询
            String resultFilePath = writeDataToNewSheet(filePath, deduplicatedList);
            log.info("处理结果已写入到文件: {}", resultFilePath);
            return resultFilePath;

        } catch (ServiceException e) {
            throw e;
        } catch (Exception e) {
            log.error("处理Excel文件时发生错误: {}", e.getMessage(), e);
            throw new ServiceException("处理Excel文件时发生错误: " + e.getMessage() + repairMsg);
        }
    }

    /**
     * 将处理后的数据写入到Excel文件的新sheet页
     * 
     * @param originalFilePath 原始文件路径
     * @param bomDeList        已处理的数据列表
     * @return 新文件路径
     */
    private String writeDataToNewSheet(String originalFilePath, List<BomDe> bomDeList) {
        try {
            log.info("准备写入 {} 条处理后的数据到新的sheet页", bomDeList.size());

            if (bomDeList.isEmpty()) {
                log.warn("没有可写入的数据");
                throw new ServiceException("没有可写入的数据" + repairMsg);
            }

            // 打开原始文件
            File originalFile = new File(originalFilePath);
            String baseName = originalFile.getName();
            String dirPath = originalFile.getParent();

            // 更安全的文件名处理
            String fileNameWithoutExt = baseName;
            if (baseName.lastIndexOf('.') > 0) {
                fileNameWithoutExt = baseName.substring(0, baseName.lastIndexOf('.'));
            }

            // 安全的新文件名处理，移除可能导致URI解析错误的字符
            String safeFileName = fileNameWithoutExt.replaceAll("[\\/:*?\"<>|\\s]", "_") + "_处理结果.xlsx";
            String newFilePath = dirPath + File.separator + safeFileName;

            // 确保目录存在
            File dir = new File(dirPath);
            if (!dir.exists()) {
                dir.mkdirs();
            }

            // 复制原始文件到新文件
            Files.copy(originalFile.toPath(), new File(newFilePath).toPath(), StandardCopyOption.REPLACE_EXISTING);

            try (FileInputStream fis = new FileInputStream(newFilePath)) {
                // 使用WorkbookFactory创建Workbook对象，捕获可能的URISyntaxException
                Workbook workbook;
                try {
                    workbook = WorkbookFactory.create(fis);
                } catch (Exception e) {
                    log.error("创建Workbook时发生URI解析错误，尝试使用WorkbookFactory.create(File)方法替代: {}", e.getMessage());
                    // 当使用InputStream方式失败时，尝试直接使用File对象方式
                    workbook = WorkbookFactory.create(new File(newFilePath));
                }

                // 检查是否已存在"处理结果"sheet，如果存在则删除
                int sheetIndex = workbook.getSheetIndex("处理结果");
                if (sheetIndex >= 0) {
                    workbook.removeSheetAt(sheetIndex);
                }

                // 创建新的sheet页
                Sheet resultSheet = workbook.createSheet("处理结果");

                // 创建标题行样式
                org.apache.poi.ss.usermodel.CellStyle headerStyle = workbook.createCellStyle();
                org.apache.poi.ss.usermodel.Font headerFont = workbook.createFont();
                headerFont.setBold(true);
                headerStyle.setFont(headerFont);
                headerStyle
                        .setFillForegroundColor(org.apache.poi.ss.usermodel.IndexedColors.GREY_25_PERCENT.getIndex());
                headerStyle.setFillPattern(org.apache.poi.ss.usermodel.FillPatternType.SOLID_FOREGROUND);

                // 创建标题行
                Row headerRow = resultSheet.createRow(0);
                String[] headers = { "ID", "序号", "图号", "名称", "规格", "材料", "层计数", "总计数", "单重", "总重", "类别", "物料编码", "备注",
                        "系统识别", "自动编码" };
                for (int i = 0; i < headers.length; i++) {
                    Cell cell = headerRow.createCell(i);
                    cell.setCellValue(headers[i]);
                    cell.setCellStyle(headerStyle);
                }

                // 创建数据样式
                org.apache.poi.ss.usermodel.CellStyle numberStyle = workbook.createCellStyle();
                numberStyle.setDataFormat(workbook.createDataFormat().getFormat("#,##0.00"));

                // 写入数据
                int rowNum = 1;
                // 写入数据行
                for (BomDe bomDe : bomDeList) {
                    Row row = resultSheet.createRow(rowNum++);

                    // ID列 - 新增在最前面
                    Cell idCell = row.createCell(0);
                    if (bomDe.getId() != null) {
                        idCell.setCellValue(bomDe.getId());
                    } else {
                        idCell.setCellValue("");
                    }

                    row.createCell(1).setCellValue(bomDe.getXuhao() != null ? bomDe.getXuhao() : "");
                    row.createCell(2).setCellValue(bomDe.getTuhao() != null ? bomDe.getTuhao() : "");
                    row.createCell(3).setCellValue(bomDe.getName() != null ? bomDe.getName() : "");
                    row.createCell(4).setCellValue(bomDe.getGuige() != null ? bomDe.getGuige() : "");
                    row.createCell(5).setCellValue(bomDe.getCailiao() != null ? bomDe.getCailiao() : "");

                    // 数值类型处理 - 优化列索引（从6开始）
                    Cell cengjishuCell = row.createCell(6);
                    if (bomDe.getCengjishu() != null) {
                        cengjishuCell.setCellValue(bomDe.getCengjishu());
                    } else {
                        cengjishuCell.setCellValue(0);
                    }

                    Cell zongjishuCell = row.createCell(7);
                    if (bomDe.getZongjishu() != null) {
                        zongjishuCell.setCellValue(bomDe.getZongjishu());
                    } else {
                        zongjishuCell.setCellValue(0);
                    }

                    Cell danzhongCell = row.createCell(8);
                    if (bomDe.getDanzhong() != null) {
                        danzhongCell.setCellValue(bomDe.getDanzhong().doubleValue());
                        danzhongCell.setCellStyle(numberStyle);
                    } else {
                        danzhongCell.setCellValue(0.0);
                    }

                    Cell zongzhongCell = row.createCell(9);
                    if (bomDe.getZongzhong() != null) {
                        zongzhongCell.setCellValue(bomDe.getZongzhong().doubleValue());
                        zongzhongCell.setCellStyle(numberStyle);
                    } else {
                        zongzhongCell.setCellValue(0.0);
                    }

                    row.createCell(10).setCellValue(bomDe.getLeibie() != null ? bomDe.getLeibie() : "");
                    row.createCell(11).setCellValue(bomDe.getBianma() != null ? bomDe.getBianma() : "");
                    row.createCell(12).setCellValue(bomDe.getBeizhu() != null ? bomDe.getBeizhu() : "");
                    row.createCell(13).setCellValue(bomDe.getXitong() != null ? bomDe.getXitong() : "");
                    row.createCell(14).setCellValue(bomDe.getSyscode() != null ? bomDe.getSyscode() : "");
                }

                // 自动调整列宽
                for (int i = 0; i <= headers.length; i++) {
                    resultSheet.autoSizeColumn(i);
                    // 设置最大列宽避免过宽
                    if (resultSheet.getColumnWidth(i) > 50 * 256) {
                        resultSheet.setColumnWidth(i, 50 * 256);
                    }
                }

                // 写入到文件
                try (FileOutputStream fos = new FileOutputStream(newFilePath)) {
                    workbook.write(fos);
                }

                log.info("处理结果已成功写入到新的sheet页: {}", newFilePath);
                return newFilePath;

            } catch (Exception e) {
                // 如果处理过程中出错，删除创建的文件
                File newFile = new File(newFilePath);
                if (newFile.exists()) {
                    newFile.delete();
                }
                throw e;
            }

        } catch (IOException e) {
            log.error("写入结果到Excel文件失败: {}", e.getMessage(), e);
            throw new ServiceException("写入处理结果失败: " + e.getMessage() + repairMsg);
        } catch (Exception e) {
            log.error("写入处理结果时发生错误: {}", e.getMessage(), e);
            throw new ServiceException("写入处理结果时发生错误: " + e.getMessage() + repairMsg);
        }
    }

    /**
     * 对BomDe数据进行去重处理
     * 
     * @param bomDeList 原始数据列表
     * @param param     参数对象，包含去重类型信息
     * @return 去重后的数据列表
     */
    private List<BomDe> deduplicateData(List<BomDe> bomDeList, BomEntity param) {
        // 使用LinkedHashMap保持原始顺序的去重
        Map<String, BomDe> deduplicatedMap = new LinkedHashMap<>();
        int duplicateCount = 0;

        String deWeightType = param.getDeWeightType();

        // 验证去重类型参数
        if (deWeightType == null || (!"project".equals(deWeightType) && !"part".equals(deWeightType))) {
            throw new ServiceException("去重类型参数不正确" + repairMsg);
        }

        for (BomDe bomDe : bomDeList) {
            // 构建去重key，处理null值，使用特殊标记处理null
            String tuhao = bomDe.getTuhao() != null ? bomDe.getTuhao().trim() : "NULL_TUHAO";
            String name = bomDe.getName() != null ? bomDe.getName().trim() : "NULL_NAME";
            String cailiao = bomDe.getCailiao() != null ? bomDe.getCailiao().trim() : "NULL_CAILIAO";
            String guige = bomDe.getGuige() != null ? bomDe.getGuige() : "NULL_GUIGE";
            String leibie = bomDe.getLeibie() != null ? bomDe.getLeibie() : "NULL_LEIBIE";
            String key;

            // 根据去重类型构建不同的key
            if ("project".equals(deWeightType)) {
                // 按项目去重：根据tuhao, name, cailiao, guige, leibie, zongjishu去重
                Integer zongjishu = bomDe.getZongjishu();
                String zongjishuStr = zongjishu != null ? String.valueOf(zongjishu) : "NULL_ZONGJISHU";
                key = tuhao + "|" + name + "|" + cailiao + "|" + guige + "|" + leibie + "|" + zongjishuStr;
            } else if ("part".equals(deWeightType)) {
                // 按零件去重：根据tuhao, name, cailiao, guige, leibie去重
                key = tuhao + "|" + name + "|" + cailiao + "|" + guige + "|" + leibie;
            } else {
                throw new ServiceException("去重类型参数不正确" + repairMsg);
            }
            // 只保留第一条记录（如果key已存在则跳过）
            if (!deduplicatedMap.containsKey(key)) {
                deduplicatedMap.put(key, bomDe);
            } else {
                duplicateCount++;
            }
        }
        // 转换为去重后的列表
        List<BomDe> deduplicatedList = new ArrayList<>(deduplicatedMap.values());
        log.info("去重后剩余 {} 条数据，共去除 {} 条重复数据", deduplicatedList.size(), duplicateCount);

        return deduplicatedList;
    }

    /**
     * 从Excel文件读取数据
     * 
     * @param file  Excel文件
     * @param param 参数对象，包含创建者信息
     * @return 读取到的BomDe列表
     */
    private List<BomDe> readExcelData(File file, BomEntity param) {
        List<BomDe> bomDeList = new ArrayList<>();

        try (FileInputStream fis = new FileInputStream(file);
                Workbook workbook = WorkbookFactory.create(fis)) {

            // 获取第一个sheet
            Sheet sheet = workbook.getSheetAt(0);
            if (sheet == null) {
                log.error("Excel文件没有sheet页: {}", file.getPath());
                throw new ServiceException("Excel文件没有sheet页" + repairMsg);
            }

            log.info("开始处理Excel文件: {}, 总行数: {}", file.getPath(), sheet.getLastRowNum());

            // 从第四行之后开始读取（索引从0开始，所以第四行是索引3）
            int startRow = 3;
            int lastRowNum = sheet.getLastRowNum();

            for (int rowNum = startRow; rowNum <= lastRowNum; rowNum++) {
                Row row = sheet.getRow(rowNum);
                if (row == null) {
                    continue;
                }

                BomDe bomDe = new BomDe();

                // 读取每一列的数据并映射到BomDe实体
                // 序号
                String xuhao = getCellValue(row.getCell(1));
                bomDe.setXuhao(xuhao);

                // 图号
                String tuhao = getCellValue(row.getCell(2));
                bomDe.setTuhao(tuhao);

                // 名称
                String name = getCellValue(row.getCell(3));
                bomDe.setName(name);

                // 规格
                String guige = getCellValue(row.getCell(4));
                bomDe.setGuige(guige);

                // 材料
                String cailiao = getCellValue(row.getCell(5));
                bomDe.setCailiao(cailiao);

                // 层计数
                String cengjishuStr = getCellValue(row.getCell(6));
                if (cengjishuStr != null && !cengjishuStr.trim().isEmpty()) {
                    try {
                        bomDe.setCengjishu(Integer.parseInt(cengjishuStr.trim()));
                    } catch (NumberFormatException e) {
                        log.warn("层计数格式错误，行号: {}, 值: {}", rowNum + 1, cengjishuStr);
                    }
                }

                // 总计数
                String zongjishuStr = getCellValue(row.getCell(7));
                if (zongjishuStr != null && !zongjishuStr.trim().isEmpty()) {
                    try {
                        bomDe.setZongjishu(Integer.parseInt(zongjishuStr.trim()));
                    } catch (NumberFormatException e) {
                        log.warn("总计数格式错误，行号: {}, 值: {}", rowNum + 1, zongjishuStr);
                    }
                }

                // 单重
                String danzhongStr = getCellValue(row.getCell(8));
                if (danzhongStr != null && !danzhongStr.trim().isEmpty()) {
                    try {
                        bomDe.setDanzhong(new BigDecimal(danzhongStr.trim()));
                    } catch (NumberFormatException e) {
                        log.warn("单重格式错误，行号: {}, 值: {}", rowNum + 1, danzhongStr);
                    }
                }

                // 总重
                String zongzhongStr = getCellValue(row.getCell(9));
                if (zongzhongStr != null && !zongzhongStr.trim().isEmpty()) {
                    try {
                        bomDe.setZongzhong(new BigDecimal(zongzhongStr.trim()));
                    } catch (NumberFormatException e) {
                        log.warn("总重格式错误，行号: {}, 值: {}", rowNum + 1, zongzhongStr);
                    }
                }

                // 类别
                String leibie = getCellValue(row.getCell(10));
                bomDe.setLeibie(leibie);

                // 物料编码
                String bianma = getCellValue(row.getCell(11));
                bomDe.setBianma(bianma);

                // 备注
                // String beizhu = getCellValue(row.getCell(12));
                // bomDe.setBeizhu(beizhu);

                // 系统识别
                String xitong = getCellValue(row.getCell(13));
                bomDe.setXitong(xitong);

                bomDe.setCreator(param.getCreator());

                // 只添加有效数据（至少包含名称或图号）
                if ((name != null && !name.trim().isEmpty()) || (tuhao != null && !tuhao.trim().isEmpty())) {
                    bomDeList.add(bomDe);
                }
            }
        } catch (IOException e) {
            log.error("读取Excel文件失败: {}", e.getMessage(), e);
            throw new ServiceException("读取Excel文件失败: " + e.getMessage() + repairMsg);
        } catch (ServiceException e) {
            // 业务异常直接抛出
            throw e;
        } catch (Exception e) {
            log.error("读取Excel数据时发生错误: {}", e.getMessage(), e);
            throw new ServiceException("读取Excel数据时发生错误: " + e.getMessage() + repairMsg);
        }

        return bomDeList;
    }

    /**
     * 获取单元格的值
     * 
     * @param cell 单元格
     * @return 单元格的字符串值
     */
    private String getCellValue(Cell cell) {
        if (cell == null) {
            return "";
        }

        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue().trim();
            case NUMERIC:
                double numericValue = cell.getNumericCellValue();
                // 判断是否为整数
                if (numericValue % 1 == 0) {
                    return String.valueOf((long) numericValue);
                } else {
                    return String.valueOf(numericValue);
                }
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            case FORMULA:
                try {
                    return cell.getStringCellValue().trim();
                } catch (Exception e) {
                    return String.valueOf(cell.getNumericCellValue());
                }
            case BLANK:
                return "";
            default:
                return "";
        }
    }

    /**
     * 获取当前登录用户的ID
     * 
     * @return 用户ID，如果无法获取则返回null
     */
    private Integer getCurrentUserId() {
        User currentUser = TokenUtils.getCurrentUser();
        return currentUser != null ? currentUser.getId() : null;
    }

    public String test() {
        BomDe excelData = new BomDe();
        excelData.setTuhao("25-20-6分");
        excelData.setName("水路软管对接三通");
        excelData.setGuige("25-20-6分");
        excelData.setCailiao("PA Type 6");
        excelData.setLeibie("标准件");

        // String code = autoCodeProcessService.generateCode(excelData);
        // log.info("====>自动生成code： [{}]", code);
        // return code;
        return null;
    }
}
